import axios from 'axios'

// 扩展 axios 配置类型
declare module 'axios' {
  interface AxiosRequestConfig {
    /**
     * 是否静默请求
     * 如果为 true，则在请求失败时不显示错误提示
     * @default false
     */
    silent?: boolean
    /**
     * 请求唯一标识符
     * 用于取消指定请求
     */
    requestId?: string
    /**
     * 请求分组
     * 用于批量取消同一分组的请求
     */
    group?: string
    /**
     * 是否启用请求合并
     * 如果为 true，相同的请求将合并为一个
     * @default true
     */
    mergeRequest?: boolean
  }
}

// 请求合并管理类
class RequestMergeManager {
  private pendingRequests = new Map<string, Promise<any>>()

  /**
   * 生成请求缓存键
   * @param config axios 配置
   * @returns 缓存键
   */
  private generateCacheKey(config: any): string {
    const { method = 'get', url = '', params = {}, data = {} } = config
    const paramsStr = JSON.stringify(params)
    const dataStr = JSON.stringify(data)
    return `${method.toUpperCase()}_${url}_${paramsStr}_${dataStr}`
  }

  /**
   * 获取或创建请求
   * @param config axios 配置
   * @param requestFn 请求函数
   * @returns Promise
   */
  getOrCreateRequest<T>(config: any, requestFn: () => Promise<T>): Promise<T> {
    // 如果禁用了请求合并，直接执行请求
    if (config.mergeRequest === false) {
      return requestFn()
    }

    const cacheKey = this.generateCacheKey(config)
    
    // 如果已有相同请求正在进行，返回已存在的 Promise
    if (this.pendingRequests.has(cacheKey)) {
      return this.pendingRequests.get(cacheKey)!
    }

    // 创建新的请求 Promise
    const requestPromise = requestFn()
      .finally(() => {
        // 请求完成后清理缓存
        this.pendingRequests.delete(cacheKey)
      })

    // 缓存请求 Promise
    this.pendingRequests.set(cacheKey, requestPromise)
    
    return requestPromise
  }

  /**
   * 清理所有待处理的请求
   */
  clear(): void {
    this.pendingRequests.clear()
  }

  /**
   * 获取当前待处理请求数量
   */
  getPendingCount(): number {
    return this.pendingRequests.size
  }

  /**
   * 获取所有待处理请求的缓存键
   */
  getPendingKeys(): string[] {
    return Array.from(this.pendingRequests.keys())
  }
}

// 请求取消管理类
class RequestCancelManager {
  private controllers = new Map<string, AbortController>()
  private groups = new Map<string, Set<string>>()
  private defaultGroup: string | null = null

  /**
   * 设置默认请求组
   * @param group 默认分组名称，null 表示不使用默认分组
   */
  setDefaultGroup(group: string | null): void {
    this.defaultGroup = group
  }

  /**
   * 获取默认请求组
   */
  getDefaultGroup(): string | null {
    return this.defaultGroup
  }

  /**
   * 创建请求取消控制器
   * @param requestId 请求唯一标识符
   * @param group 请求分组，如果未指定则使用默认分组
   * @returns AbortController
   */
  createController(requestId: string, group?: string): AbortController {
    const controller = new AbortController()
    this.controllers.set(requestId, controller)
    
    // 使用指定分组或默认分组
    const finalGroup = group || this.defaultGroup
    
    // 如果有分组，将请求添加到分组中
    if (finalGroup) {
      if (!this.groups.has(finalGroup)) {
        this.groups.set(finalGroup, new Set())
      }
      this.groups.get(finalGroup)!.add(requestId)
    }
    
    return controller
  }

  /**
   * 取消指定请求
   * @param requestId 请求唯一标识符
   */
  cancel(requestId: string): void {
    const controller = this.controllers.get(requestId)
    if (controller) {
      controller.abort()
      this.remove(requestId)
    }
  }

  /**
   * 取消指定分组的所有请求
   * @param group 分组名称
   */
  cancelGroup(group: string): void {
    const requestIds = this.groups.get(group)
    if (requestIds) {
      requestIds.forEach(requestId => {
        const controller = this.controllers.get(requestId)
        if (controller) {
          controller.abort()
          this.controllers.delete(requestId)
        }
      })
      this.groups.delete(group)
    }
  }

  /**
   * 取消所有请求
   */
  cancelAll(): void {
    this.controllers.forEach((controller) => {
      controller.abort()
    })
    this.controllers.clear()
    this.groups.clear()
  }

  /**
   * 移除已完成的请求控制器
   * @param requestId 请求唯一标识符
   */
  remove(requestId: string): void {
    this.controllers.delete(requestId)
    
    // 从所有分组中移除该请求
    this.groups.forEach((requestIds, group) => {
      if (requestIds.has(requestId)) {
        requestIds.delete(requestId)
        // 如果分组为空，删除分组
        if (requestIds.size === 0) {
          this.groups.delete(group)
        }
      }
    })
  }

  /**
   * 获取当前活跃请求数量
   */
  getActiveCount(): number {
    return this.controllers.size
  }

  /**
   * 获取指定分组的活跃请求数量
   * @param group 分组名称
   */
  getGroupActiveCount(group: string): number {
    return this.groups.get(group)?.size || 0
  }

  /**
   * 获取所有分组信息
   */
  getGroupsInfo(): Record<string, number> {
    const info: Record<string, number> = {}
    this.groups.forEach((requestIds, group) => {
      info[group] = requestIds.size
    })
    return info
  }
}

// 创建请求取消管理器实例
const cancelManager = new RequestCancelManager()
// 创建请求合并管理器实例
const mergeManager = new RequestMergeManager()

const request = axios.create({
  baseURL: '/api', //import.meta.env.VITE_API_URL,
  // timeout: 10000,
  // 启用浏览器默认的凭证处理
  withCredentials: true
})

// 重写 axios 的各种请求方法以支持请求合并
const originalGet = request.get.bind(request)
const originalPost = request.post.bind(request)
const originalPut = request.put.bind(request)
const originalDelete = request.delete.bind(request)
const originalPatch = request.patch.bind(request)
const originalHead = request.head.bind(request)
const originalOptions = request.options.bind(request)

request.get = function(url: string, config: any = {}) {
  const mergedConfig = { ...config, method: 'get', url }
  return mergeManager.getOrCreateRequest(mergedConfig, () => {
    // 为请求添加取消功能
    const requestId = config.requestId || `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
    const controller = cancelManager.createController(requestId, config.group)
    const finalConfig = { ...config, requestId, signal: controller.signal }
    
    return originalGet(url, finalConfig)
      .then(response => {
        cancelManager.remove(requestId)
        return response
      })
      .catch(error => {
        cancelManager.remove(requestId)
        throw error
      })
  })
}

request.post = function(url: string, data?: any, config: any = {}) {
  const mergedConfig = { ...config, method: 'post', url, data }
  return mergeManager.getOrCreateRequest(mergedConfig, () => {
    const requestId = config.requestId || `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
    const controller = cancelManager.createController(requestId, config.group)
    const finalConfig = { ...config, requestId, signal: controller.signal }
    
    return originalPost(url, data, finalConfig)
      .then(response => {
        cancelManager.remove(requestId)
        return response
      })
      .catch(error => {
        cancelManager.remove(requestId)
        throw error
      })
  })
}

request.put = function(url: string, data?: any, config: any = {}) {
  const mergedConfig = { ...config, method: 'put', url, data }
  return mergeManager.getOrCreateRequest(mergedConfig, () => {
    const requestId = config.requestId || `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
    const controller = cancelManager.createController(requestId, config.group)
    const finalConfig = { ...config, requestId, signal: controller.signal }
    
    return originalPut(url, data, finalConfig)
      .then(response => {
        cancelManager.remove(requestId)
        return response
      })
      .catch(error => {
        cancelManager.remove(requestId)
        throw error
      })
  })
}

request.delete = function(url: string, config: any = {}) {
  const mergedConfig = { ...config, method: 'delete', url }
  return mergeManager.getOrCreateRequest(mergedConfig, () => {
    const requestId = config.requestId || `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
    const controller = cancelManager.createController(requestId, config.group)
    const finalConfig = { ...config, requestId, signal: controller.signal }
    
    return originalDelete(url, finalConfig)
      .then(response => {
        cancelManager.remove(requestId)
        return response
      })
      .catch(error => {
        cancelManager.remove(requestId)
        throw error
      })
  })
}

request.patch = function(url: string, data?: any, config: any = {}) {
  const mergedConfig = { ...config, method: 'patch', url, data }
  return mergeManager.getOrCreateRequest(mergedConfig, () => {
    const requestId = config.requestId || `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
    const controller = cancelManager.createController(requestId, config.group)
    const finalConfig = { ...config, requestId, signal: controller.signal }
    
    return originalPatch(url, data, finalConfig)
      .then(response => {
        cancelManager.remove(requestId)
        return response
      })
      .catch(error => {
        cancelManager.remove(requestId)
        throw error
      })
  })
}

request.head = function(url: string, config: any = {}) {
  const mergedConfig = { ...config, method: 'head', url }
  return mergeManager.getOrCreateRequest(mergedConfig, () => {
    const requestId = config.requestId || `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
    const controller = cancelManager.createController(requestId, config.group)
    const finalConfig = { ...config, requestId, signal: controller.signal }
    
    return originalHead(url, finalConfig)
      .then(response => {
        cancelManager.remove(requestId)
        return response
      })
      .catch(error => {
        cancelManager.remove(requestId)
        throw error
      })
  })
}

request.options = function(url: string, config: any = {}) {
  const mergedConfig = { ...config, method: 'options', url }
  return mergeManager.getOrCreateRequest(mergedConfig, () => {
    const requestId = config.requestId || `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
    const controller = cancelManager.createController(requestId, config.group)
    const finalConfig = { ...config, requestId, signal: controller.signal }
    
    return originalOptions(url, finalConfig)
      .then(response => {
        cancelManager.remove(requestId)
        return response
      })
      .catch(error => {
        cancelManager.remove(requestId)
        throw error
      })
  })
}

// request.interceptors.request.use(
//   (config) => {
//     if (stores.token) {
//       config.headers.Authorization = `Bearer ${stores.token}`
//     }
//     return config;
//   },
//   (error) => {
//     return Promise.reject(error);
//   }
// )

// request.interceptors.response.use(
//   (response) => {
//     return response;
//   },
//   (error) => {
//     // 检查是否设置了 silent 参数
//     if (!error.config?.silent) {
//       // 如果是取消请求，不显示错误提示
//       if (error.name === 'CanceledError' || error.code === 'ERR_CANCELED') {
//         return Promise.reject(error)
//       }
//       const msg = error.response?.data?.message || '请求失败';
//       message.error({ content: msg, key: msg });
//     }
//     return Promise.reject(error)
//   }
// )

// 导出请求取消相关方法
export const requestCancel = {
  /**
   * 设置默认请求组
   * @param group 默认分组名称，null 表示不使用默认分组
   */
  setDefaultGroup: (group: string | null) => cancelManager.setDefaultGroup(group),
  
  /**
   * 获取默认请求组
   */
  getDefaultGroup: () => cancelManager.getDefaultGroup(),
  
  /**
   * 取消指定请求
   * @param requestId 请求唯一标识符
   */
  cancel: (requestId: string) => cancelManager.cancel(requestId),
  
  /**
   * 取消指定分组的所有请求
   * @param group 分组名称
   */
  cancelGroup: (group: string) => cancelManager.cancelGroup(group),
  
  /**
   * 取消所有请求
   */
  cancelAll: () => cancelManager.cancelAll(),
  
  /**
   * 获取当前活跃请求数量
   */
  getActiveCount: () => cancelManager.getActiveCount(),
  
  /**
   * 获取指定分组的活跃请求数量
   * @param group 分组名称
   */
  getGroupActiveCount: (group: string) => cancelManager.getGroupActiveCount(group),
  
  /**
   * 获取所有分组信息
   */
  getGroupsInfo: () => cancelManager.getGroupsInfo()
}

// 导出请求合并相关方法
export const requestMerge = {
  /**
   * 清理所有待处理的请求
   */
  clear: () => mergeManager.clear(),
  
  /**
   * 获取当前待处理请求数量
   */
  getPendingCount: () => mergeManager.getPendingCount(),
  
  /**
   * 获取所有待处理请求的缓存键
   */
  getPendingKeys: () => mergeManager.getPendingKeys()
}

export default request
